<template>
  <div ref="canvas" />
</template>

<script lang="ts" setup>
import * as THREE from "three";
import TWEEN from '@tweenjs/tween.js';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GUI }  from "three/examples/jsm/libs/lil-gui.module.min.js";
import { ref, onMounted } from "vue";

// 画布
const canvas = ref<any>('');
// 场景
const scene = new THREE.Scene();
// 相机
const camera = new THREE.PerspectiveCamera();
camera.position.set(5, 0, 0);
camera.lookAt(0, 0, 0);

// 点击相机
let isClickCamera = false;
/**
 * 鼠标按下
 * @param event
 */
const onMouseDown = (event) => {
  event.preventDefault(); // 取消默认事件
  console.log("---onMouseDown---");
  isClickCamera = true;
}

let mouse;
let raycaster;
/**
 * 鼠标放开
 * @param event
 */
const onMouseUp = (event) => {
  event.preventDefault(); // 取消默认事件
  console.log("---onMouseUp---");
  if (isClickCamera) {
    console.log("---移动相机---", event);
    // 红色代表X轴，绿色代表Y轴，蓝色代表Z轴
    mouse = new THREE.Vector3(); // 三维坐标对象
    // 屏幕坐标到标准化设备坐标(Normalized Device Coordinates, NDC)转换
    mouse.set((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);
    mouse.unproject(this.camera);

    raycaster = new THREE.Raycaster(this.camera.position, this.mouse.sub(this.camera.position).normalize()); // 投手
    const intersects = this.raycaster.intersectObjects(this.scene.children);

    if (intersects.length > 0) {
      const selected = intersects[0]; // 取第一个物体
      console.log("x坐标:" + selected.point.x);
      console.log("y坐标:" + selected.point.y);
      console.log("z坐标:" + selected.point.z);
      camera.position.set(selected.point.x, selected.point.y, selected.point.z);
    }
  }
}
/**
 * 鼠标移动
 * @param event
 */
const onMouseMove = (event) => {
  event.preventDefault(); // 取消默认事件
  console.log("---onMouseMove---");
  isClickCamera = false;
}

// 相机控件
let orbitControl;
const initOrbitControl = () => {
  // 相机控件
  orbitControl = new OrbitControls(camera, renderer.domElement);
  orbitControl.update();
  orbitControl.target = new THREE.Vector3(0, 0, 0);
  // 相机最近
  orbitControl.minDistance = 18;
  // 相机最远 太远就会显示出球体
  orbitControl.maxDistance = 90;
  // 图片自动旋转
  orbitControl.autoRotate = control.isRotation;
  // 使动画循环使用时阻尼或自转 意思是否有惯性
  orbitControl.enableDamping = true;
  // 是否开启右键拖拽
  orbitControl.enablePan = control.isEnablePan;
  // 阻尼系数
  orbitControl.autoRotateSpeed = 0.5;
};

/**
 * 更新相机动画
 * @param position
 * @param target
 */
const tweenCamera = (position, target) => {
  new TWEEN.Tween(camera.position).to({
    x: position.x,
    y: position.y,
    z: position.z
  }, 600).easing(TWEEN.Easing.Sinusoidal.InOut).start();

  new TWEEN.Tween(orbitControl.target).to({
    x: target.x,
    y: target.y,
    z: target.z
  }, 600).easing(TWEEN.Easing.Sinusoidal.InOut).start();
}

// 几何体
const geometry = new THREE.SphereGeometry(100, 100, 100);
// 反转x轴上的几何图形，使所有面都指向内侧
geometry.scale( 1, 1, -1 );
// 纹理
const texture = new THREE.TextureLoader().load(new URL("@/assets/house.jpg", import.meta.url).href)
// 材质
const material = new THREE.MeshBasicMaterial({ map : texture });
// mesh
const mesh = new THREE.Mesh(geometry, material);
// 将 mesh 添加到场景中
scene.add(mesh);
// 渲染器
const renderer = new THREE.WebGLRenderer({ antialias : true });
renderer.setClearColor(0xffffff);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// 控制
const control = {
  isRotation: false, // 是否自动旋转
  isEnablePan: false, // 是否开启右键拖拽
};
// 初始化相机
initOrbitControl();
// gui界面
const gui = new GUI();
// @ts-ignore
gui.add(control, 'isRotation').name("自动旋转").onChange((e) => {
  control.isRotation = e;
  // 需重新调用控制器才能生效
  initOrbitControl();
});
// @ts-ignore
gui.add(control, 'isEnablePan').name("开启右键拖拽");

const onWindowResize = () => {
  // 窗口缩放的时候,保证场景也跟着一起缩放
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

const render = () => {
  requestAnimationFrame(render);
  orbitControl.update();
  TWEEN.update();
  renderer.render(scene, camera);
}

onMounted(() => {
  canvas.value.appendChild(renderer.domElement);

  // 鼠标事件监听
  renderer.domElement.addEventListener('pointerdown', onMouseDown, false);
  renderer.domElement.addEventListener('pointerup', onMouseUp, false);
  renderer.domElement.addEventListener('pointermove', onMouseMove, false);
  // 监听布局变化
  window.addEventListener('resize', onWindowResize, false);

  render();
})

</script>
